using System;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading.Tasks;

namespace WINPE_TOOLBOX
{
    public class Aria2
    {
        private string _aria2Path;
        private string _filePath;

        public Aria2()
        {
            // 初始化，创建 aria2 文件路径
            _aria2Path = Path.Combine(Path.GetTempPath(), "aria2c_" + Path.GetRandomFileName() + ".exe");

            // 复制 aria2c.exe 到临时路径
            File.Copy(GlobalPaths.Tools + "aria2c.exe", _aria2Path, true);
            Console.WriteLine(_aria2Path);
        }

        public void Start(string url, string saveDir, string saveName, int thread = 8, Action<Aria2Attrib> callback = null)
        {
            _filePath = Path.Combine(saveDir, saveName);

            var cmd = new StringBuilder();
            cmd.Append($"\"{_aria2Path}\" ");
            cmd.Append($"\"{url}\" ");
            cmd.Append($"-d \"{saveDir}\" -o \"{saveName}\" ");
            cmd.Append($"-s {thread} -x {thread} ");
            cmd.Append("--file-allocation=none ");
            cmd.Append("-c ");
            cmd.Append("--check-certificate=false ");
            cmd.Append("--force-save=false ");

            Console.WriteLine(cmd.ToString());

            var tempAria2Attrib = new Aria2Attrib
            {
                State = "request",
                Speed = "",
                Percentage = 0,
                Remainder = "",
                Size = "",
                NewSize = "",
                Message = ""
            };

            RunCmd(cmd.ToString(), print =>
            {
                tempAria2Attrib.Message = print;
                Console.WriteLine(print);

                if (print.Contains("DL:") && print.Contains("ETA"))
                {
                    tempAria2Attrib.State = "doing";
                    tempAria2Attrib.Speed = TakeMidStr(print, "DL:", "iB ETA") + "B/秒";
                    tempAria2Attrib.Percentage = int.Parse(TakeMidStr(print, "B(", "%)"));
                    tempAria2Attrib.Remainder = TakeMidStr(print, "ETA:", "]");
                    tempAria2Attrib.Size = TakeMidStr(print, "/", "iB(") + "B";
                    tempAria2Attrib.NewSize = TakeRightStr(TakeMidStr(print, "[#", "iB/"), " ") + "B";
                }
                else
                {
                    tempAria2Attrib.State = "request";
                }

                callback?.Invoke(tempAria2Attrib);
            }, e =>
            {
                if (e == 0)
                {
                    tempAria2Attrib.State = "done";
                    Console.WriteLine("成功", e);
                }
                else
                {
                    tempAria2Attrib.State = "error";
                    Console.WriteLine("失败", e);
                }
                callback?.Invoke(tempAria2Attrib);
            });
        }

        public void Stop(Action<bool> callback)
        {
            var cmd = $"taskkill /T /F /IM \"{Path.GetFileName(_aria2Path)}\"";

            RunCmd(cmd, print => Console.WriteLine(print), e =>
            {
                DelFiles(_filePath + ".aria2");
                callback(DelFiles(_filePath));
            });
        }

        private void RunCmd(string cmd, Action<string> outputCallback, Action<int> exitCallback)
        {
            var processInfo = new ProcessStartInfo("cmd.exe", "/c " + cmd)
            {
                RedirectStandardOutput = true,
                RedirectStandardError = true,
                UseShellExecute = false,
                CreateNoWindow = true,
                StandardOutputEncoding = Encoding.UTF8,
                StandardErrorEncoding = Encoding.UTF8
            };

            var process = new Process { StartInfo = processInfo };

            process.OutputDataReceived += (sender, args) =>
            {
                if (args.Data != null)
                {
                    outputCallback(args.Data);
                }
            };

            process.ErrorDataReceived += (sender, args) =>
            {
                if (args.Data != null)
                {
                    Console.Error.WriteLine(args.Data);
                }
            };

            process.Exited += (sender, args) =>
            {
                process.WaitForExit(); // 确保进程完成
                exitCallback(process.ExitCode);
                process.Dispose();
            };

            process.Start();
            process.BeginOutputReadLine();
            process.BeginErrorReadLine();
        }

        private bool DelFiles(string path)
        {
            try
            {
                if (File.Exists(path))
                {
                    File.Delete(path);
                }
                return true;
            }
            catch (Exception ex)
            {
                Console.Error.WriteLine(ex);
                return false;
            }
        }

        private string TakeMidStr(string str, string leftStr, string rightStr)
        {
            int start = str.IndexOf(leftStr) + leftStr.Length;
            int end = str.IndexOf(rightStr, start);
            return str.Substring(start, end - start);
        }

        private string TakeRightStr(string str, string taggedStr)
        {
            return str.Substring(str.IndexOf(taggedStr) + taggedStr.Length);
        }
    }

    public class Aria2Attrib
    {
        public string State { get; set; }
        public string Speed { get; set; }
        public int Percentage { get; set; }
        public string Remainder { get; set; }
        public string Size { get; set; }
        public string NewSize { get; set; }
        public string Message { get; set; }
    }
}
